﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Data;
using System.Windows.Controls;
using System.Xml.Linq;
using System.Windows;
using System.Windows.Media;

namespace Twi.COMMON.WPF
{
    public static class TreeViewExtensions
    {
        public static void CheckTreeView(this TreeView me, IEnumerable<string> deptIDList)
        {
            string key = me.SelectedValuePath.Split(new string[] { "Tag.Element[", "].Value" }, StringSplitOptions.RemoveEmptyEntries)[0];
            foreach (CheckBoxTreeViewItem tvi in me.Items)
            {
                CheckTreeViewItem(tvi, deptIDList, key);
            }
        }

        public static void CheckTreeViewItem(this CheckBoxTreeViewItem me, IEnumerable<string> deptIDList, string key)
        {
            if (deptIDList != null && deptIDList.Contains((me.Tag as XElement).Element(key).Value))//那么它的子节点都将被默认勾选
            {
                me.IsChecked = true;
                if (!me.CascadeCheck)//如果不是自动级联，必须在此处级联子项是否应该被勾选
                {
                    foreach (CheckBoxTreeViewItem tvi in me.Children)
                    {
                        CheckTreeViewItem(tvi, deptIDList, key);
                    }
                }
            }
            else
            {
                foreach (CheckBoxTreeViewItem tvi in me.Children)
                {
                    CheckTreeViewItem(tvi, deptIDList, key);
                }
            }
        }

        #region 获得选中树节点结构
        /// <summary>
        /// 获得选中树节点结构
        /// </summary>
        /// <param name="me"></param>
        /// <returns></returns>
        public static List<XElement> GetCheckedList(this TreeView me)
        {
            List<XElement> xeCheckedList = new List<XElement>();
            foreach (CheckBoxTreeViewItem tvi in me.Items)
            {
                GetCheckedList(tvi, xeCheckedList);
            }
            return xeCheckedList;
        }

        private static void GetCheckedList(this CheckBoxTreeViewItem me, List<XElement> xeCheckedList)
        {
            if (me.IsChecked == true)
            {
                xeCheckedList.Add(me.Tag as XElement);
            }
            foreach (CheckBoxTreeViewItem tvi in me.Children)
            {
                GetCheckedList(tvi, xeCheckedList);
            }
        }
        #endregion 
                
        #region 清空选中树节点结构
        /// <summary>
        /// 清空选中树节点结构
        /// </summary>
        /// <param name="me"></param>
        /// <returns></returns>
        public static void ClearChecked(this TreeView me)
        {
            foreach (CheckBoxTreeViewItem tvi in me.Items)
            {
                ClearTVIChecked(tvi);
            }
            me.Items.Refresh();
        }

        private static void ClearTVIChecked(CheckBoxTreeViewItem me)
        {
            if (me.IsChecked == true)
            {
                me.IsChecked = false;
            }
            foreach (CheckBoxTreeViewItem tvi in me.Children)
            {
                ClearTVIChecked(tvi);
            }
        }
        #endregion 

        public static List<string> GetCheckedList_Key(this TreeView me)
        {
            string key = me.SelectedValuePath.Split(new string[] { "Tag.Element[", "].Value" }, StringSplitOptions.RemoveEmptyEntries)[0];
            List<string> xeCheckedList = new List<string>();
            foreach (CheckBoxTreeViewItem tvi in me.Items)
            {
                SetCheckedList_Key(tvi, xeCheckedList, key);
            }
            return xeCheckedList;
        }

        private static void SetCheckedList_Key(this CheckBoxTreeViewItem me, List<string> xeCheckedList, string key)
        {
            if (me.IsChecked == true)
            {
                xeCheckedList.Add((me.Tag as XElement).Element(key).Value);
            }
            foreach (CheckBoxTreeViewItem tvi in me.Children)
            {
                SetCheckedList_Key(tvi, xeCheckedList, key);
            }
        }

        public static void BindWithCheckBox(this TreeView me, IEnumerable<XElement> source, string displayElementName, string key, string parentKey, bool cascadeCheck = true)
        {
            IList<CheckBoxTreeViewItem> list = new List<CheckBoxTreeViewItem>();
            me.SelectedValuePath = string.Format("Tag.Element[{0}].Value", key);

            var items = source.Where(x => x.Element(parentKey).Value == "0");
            if (items.Count() == 0) //只是整个表的部分数据组成树结构, 所以用0无法找到根节点 
            {
                var keys = source.Select(x => x.Element(key).Value);
                items = source.Where(x => !keys.Contains(x.Element(parentKey).Value)); //父节点标识值不在该集合中的就是根节点 
            }
            foreach (var item in items)
            {
                CheckBoxTreeViewItem tvi = new CheckBoxTreeViewItem(item.Element(displayElementName).Value, cascadeCheck) { Tag = item };
                //tvi.IsInitiallySelected = true;
                tvi.IsExpanded = false;
                tvi.SetChildrenWithCheckBox(source, displayElementName, key, parentKey, cascadeCheck);

                tvi.Initialize();
                list.Add(tvi);

            }
            me.ItemsSource = list;
        }


        private static void SetChildrenWithCheckBox(this CheckBoxTreeViewItem me, IEnumerable<XElement> source, string displayElementName, string key, string parentKey, bool cascadeCheck)
        {
            XElement dataItem = me.Tag as XElement;
            var items = source.Where(x => x.Element(parentKey).Value == dataItem.Element(key).Value);
            foreach (var item in items)
            {
                CheckBoxTreeViewItem tvi = new CheckBoxTreeViewItem(item.Element(displayElementName).Value, cascadeCheck) { Tag = item };
                tvi.IsExpanded = false;
                tvi.SetChildrenWithCheckBox(source, displayElementName, key, parentKey, cascadeCheck);
                me.Children.Add(tvi);
            }
        }

        public static void Bind(this TreeView me, IEnumerable<XElement> source, string displayElementName, string key, string parentKey)
        {
            Bind(me, source, displayElementName, null, key, parentKey, -1);
        }
        public static void Bind(this TreeView me, IEnumerable<XElement> source, string displayElementName, string key, string parentKey, string filterKey, string filterElement)
        {
            Bind(me, source, displayElementName, null, key, parentKey, -1, filterKey, filterElement);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="me"></param>
        /// <param name="source"></param>
        /// <param name="displayElementName">XElment中用于显示的名称</param>
        /// <param name="converterParamenter">转化参数</param>
        /// <param name="key"></param>
        /// <param name="parentKey">父节点key</param>
        /// <param name="expandChildNodesLevels">需要展开的子节点层数</param>
        public static void Bind(this TreeView me, IEnumerable<XElement> source, string displayElementName, string converterParamenter, string key, string parentKey, int expandChildNodesLevels)
        {
            var items = source.Where(x => x.Element(parentKey).Value == "0");
            if (items.Count() == 0) //只是整个表的部分数据组成树结构, 所以用0无法找到根节点 
            {
                var keys = source.Select(x => x.Element(key).Value);
                items = source.Where(x => !keys.Contains(x.Element(parentKey).Value)); //父节点标识值不在该集合中的就是根节点 
            }

            int decreasedExpandChildNodesLevels = expandChildNodesLevels - 1;
            foreach (var item in items)
            {
                TreeViewItem tvi = new TreeViewItem();
                if (item.Element("DefaultFlag").GetValue<int>(0) == 1)
                {
                    tvi.FontWeight = FontWeights.Bold;
                }
                Binding bdDisplay = new Binding();
                if (!string.IsNullOrEmpty(displayElementName))//是否需要指定显示路径
                {
                    bdDisplay.Path = new PropertyPath(string.Format("Element[{0}].Value", displayElementName));
                }
                if (!string.IsNullOrEmpty(converterParamenter))//是否需要提供转换参数
                {
                    bdDisplay.Converter = new XElementExpressionConverter();
                    bdDisplay.ConverterParameter = converterParamenter;
                }
                tvi.SetBinding(TreeViewItem.HeaderProperty, bdDisplay);
                tvi.DataContext = item;

                if (decreasedExpandChildNodesLevels > 0)
                {
                    tvi.IsExpanded = true;
                }
                tvi.SetChildren(source, displayElementName, converterParamenter, key, parentKey, decreasedExpandChildNodesLevels, null);
                me.Items.Add(tvi);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="me"></param>
        /// <param name="source"></param>
        /// <param name="displayElementName">XElment中用于显示的名称</param>
        /// <param name="converterParamenter">转化参数</param>
        /// <param name="key"></param>
        /// <param name="parentKey">父节点key</param>
        /// <param name="expandChildNodesLevels">需要展开的子节点层数</param>
        /// <param name="filterKey">关键字过滤</param>
        /// <param name="filterElement">过滤编号的字段</param>
        public static void BindSampleType(this TreeView me, IEnumerable<XElement> source, string displayElementName, string converterParamenter, string key, string parentKey, int expandChildNodesLevels, string filterKey, string filterElement, Action<TreeViewItem> handleLeafNode = null)
        {
            //me.SelectedValuePath = string.Format("DataContext.Element[{0}].Value", key);还是让XAML文件决定吧
            IEnumerable<XElement> filterSource = source;
            if (!string.IsNullOrEmpty(filterKey))
            {

                filterSource = source.Where(x => x.Element(displayElementName).GetValue().Contains(filterKey) || x.Element("SampleTypeNo").GetValue().Contains(filterKey) || x.Element("SampleTypeCode").GetValue().Contains(filterKey));
                var filterSourceList = filterSource.ToList();
                foreach (var _item in filterSource)
                {
                    string code = _item.Element(filterElement).Value;
                    for (int i = 0; i < code.Length - 1; i = i + 2)
                    {
                        filterSourceList.Add(source.Where(x => x.Element(filterElement).Value.Equals(code.Substring(0, i + 2))).FirstOrDefault());
                    }
                    filterSourceList.AddRange(source.Where(x => x.Element(parentKey).Value == _item.Element(key).Value).ToList());
                }
                filterSource = filterSourceList as IEnumerable<XElement>;
                filterSource = filterSource.Where(x => x != null);
                source = filterSource;
                source = source.Distinct();
            }
            var items = source.Where(x => x.Element(parentKey).Value == "0");
            int decreasedExpandChildNodesLevels = expandChildNodesLevels - 1;
            foreach (var item in items)
            {
                TreeViewItem tvi = new TreeViewItem();
                Binding bdDisplay = new Binding();
                if (!string.IsNullOrEmpty(displayElementName))//是否需要指定显示路径
                {
                    bdDisplay.Path = new PropertyPath(string.Format("Element[{0}].Value", displayElementName));
                }
                if (!string.IsNullOrEmpty(converterParamenter))//是否需要提供转换参数
                {
                    bdDisplay.Converter = new XElementExpressionConverter();
                    bdDisplay.ConverterParameter = converterParamenter;
                }
                tvi.SetBinding(TreeViewItem.HeaderProperty, bdDisplay);
                tvi.DataContext = item;

                if (decreasedExpandChildNodesLevels > 0)
                {
                    tvi.IsExpanded = true;
                }
                tvi.SetChildren(source, displayElementName, converterParamenter, key, parentKey, decreasedExpandChildNodesLevels, handleLeafNode);
                me.Items.Add(tvi);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="me"></param>
        /// <param name="source"></param>
        /// <param name="displayElementName">XElment中用于显示的名称</param>
        /// <param name="converterParamenter">转化参数</param>
        /// <param name="key"></param>
        /// <param name="parentKey">父节点key</param>
        /// <param name="expandChildNodesLevels">需要展开的子节点层数</param>
        /// <param name="filterKey">关键字过滤</param>
        /// <param name="filterElement">过滤编号的字段</param>
        public static void Bind(this TreeView me, IEnumerable<XElement> source, string displayElementName, string converterParamenter, string key, string parentKey, int expandChildNodesLevels, string filterKey, string filterElement, Action<TreeViewItem> handleLeafNode = null, int showChildNodesLevels = 0)
        {
            //me.SelectedValuePath = string.Format("DataContext.Element[{0}].Value", key);还是让XAML文件决定+1
            IEnumerable<XElement> filterSource = source;
            if (!string.IsNullOrEmpty(filterKey))
            {

                filterSource = source.Where(x => x.Element(displayElementName).Value.Contains(filterKey));
                var filterSourceList = filterSource.ToList();
                foreach (var _item in filterSource)
                {
                    string code = _item.Element(filterElement).Value;
                    for (int i = 0; i < code.Length - 1; i = i + 2)
                    {
                        filterSourceList.Add(source.Where(x => x.Element(filterElement).Value.Equals(code.Substring(0, i + 2))).FirstOrDefault());
                    }
                    filterSourceList.AddRange(source.Where(x => x.Element(parentKey).Value == _item.Element(key).Value).ToList());
                }
                filterSource = filterSourceList as IEnumerable<XElement>;
                filterSource = filterSource.Where(x => x != null);
                source = filterSource;
                source = source.Distinct();
            }
            var items = source.Where(x => x.Element(parentKey).Value == "0");
            int decreasedExpandChildNodesLevels = expandChildNodesLevels - 1;
            foreach (var item in items)
            {
                TreeViewItem tvi = new TreeViewItem();
                if (item.Element("DefaultFlag").GetValue<int>(0) == 1)
                {
                    tvi.FontWeight = FontWeights.Bold;
                }
                Binding bdDisplay = new Binding();
                if (!string.IsNullOrEmpty(displayElementName))//是否需要指定显示路径
                {
                    bdDisplay.Path = new PropertyPath(string.Format("Element[{0}].Value", displayElementName));
                }
                if (!string.IsNullOrEmpty(converterParamenter))//是否需要提供转换参数
                {
                    bdDisplay.Converter = new XElementExpressionConverter();
                    bdDisplay.ConverterParameter = converterParamenter;
                }
                tvi.SetBinding(TreeViewItem.HeaderProperty, bdDisplay);
                tvi.DataContext = item;

                if (decreasedExpandChildNodesLevels > 0)
                {
                    tvi.IsExpanded = true;
                }
                
                tvi.SetChildren(source, displayElementName, converterParamenter, key, parentKey, decreasedExpandChildNodesLevels, handleLeafNode, showChildNodesLevels == 0 ? showChildNodesLevels
                        : (showChildNodesLevels - 1));
                me.Items.Add(tvi);
            }
        }

        private static void SetChildren(this TreeViewItem me, IEnumerable<XElement> source, string displayElementName, string converterParamenter, string key, string parentKey, int expandChildNodesLevels, Action<TreeViewItem> handleLeafNode, int showChildNodesLevels = 0)
        {
            XElement dataItem = me.DataContext as XElement;
            var items = source.Where(x => x.Element(parentKey).Value == dataItem.Element(key).Value);
            if (items.Count() > 0) //不是叶子节点
            {
                int decreasedExpandChildNodesLevels = expandChildNodesLevels - 1;
                foreach (var item in items)
                {
                    TreeViewItem tvi = new TreeViewItem();
                    if (item.Element("DefaultFlag").GetValue<int>(0) == 1)
                    {
                        tvi.FontWeight = FontWeights.Bold;
                    }

                    Binding bdDisplay = new Binding();
                    if (!string.IsNullOrEmpty(displayElementName))
                    {
                        bdDisplay.Path = new PropertyPath(string.Format("Element[{0}].Value", displayElementName));
                    }
                    if (!string.IsNullOrEmpty(converterParamenter))
                    {
                        bdDisplay.Converter = new XElementExpressionConverter();
                        bdDisplay.ConverterParameter = converterParamenter;
                    }
                    tvi.SetBinding(TreeViewItem.HeaderProperty, bdDisplay);
                    tvi.DataContext = item;
                    if (decreasedExpandChildNodesLevels > 0)
                    {
                        tvi.IsExpanded = true;
                    }
                    tvi.SetChildren(source, displayElementName, converterParamenter, key, parentKey, decreasedExpandChildNodesLevels, handleLeafNode, showChildNodesLevels == 0 ? showChildNodesLevels
                        : (showChildNodesLevels - 1));
                    me.Items.Add(tvi);
                }
            }
            else
            {
                if (handleLeafNode != null)
                {
                    handleLeafNode(me);
                }
            }
        }

        #region 分步加载子节点
        /// <summary>
        /// 分步加载子节点
        /// </summary>
        /// <param name="me"></param>
        /// <param name="source"></param>
        /// <param name="displayElementName"></param>
        /// <param name="converterParamenter"></param>
        /// <param name="key"></param>
        /// <param name="parentKey"></param>
        /// <param name="loadSubChildNodesLevels"></param>
        public static void LoadSub(this TreeViewItem me, IEnumerable<XElement> source, string displayElementName, string converterParamenter
            , string key, string parentKey, int loadSubChildNodesLevels = 1)
        {
            XElement dataItem = me.DataContext as XElement;
            me.DataContext = dataItem;

            int decreasedLoadSubChildNodesLevels = loadSubChildNodesLevels - 1;
            var items = source.Where(x => x.Element(parentKey).GetValue() == dataItem.Element(key).GetValue());
            foreach (var item in items)
            {
                TreeViewItem tvi = new TreeViewItem();
                if (item.Element("DefaultFlag").GetValue<int>(0) == 1)
                {
                    tvi.FontWeight = FontWeights.Bold;
                }
                Binding bdDisplay = new Binding();
                if (!string.IsNullOrEmpty(displayElementName))//是否需要指定显示路径
                {
                    bdDisplay.Path = new PropertyPath(string.Format("Element[{0}].Value", displayElementName));
                }
                if (!string.IsNullOrEmpty(converterParamenter))//是否需要提供转换参数
                {
                    bdDisplay.Converter = new XElementExpressionConverter();
                    bdDisplay.ConverterParameter = converterParamenter;
                }
                tvi.SetBinding(TreeViewItem.HeaderProperty, bdDisplay);
                tvi.DataContext = item;
                tvi.IsExpanded = true;
                //加载子节点级数
                if (decreasedLoadSubChildNodesLevels > 0)
                {
                    tvi.LoadSub_SetChildren(source, displayElementName, converterParamenter, key, parentKey, decreasedLoadSubChildNodesLevels);
                }
                me.Items.Add(tvi);
            }
        }
        private static void LoadSub_SetChildren(this TreeViewItem me, IEnumerable<XElement> source, string displayElementName, string converterParamenter, string key, string parentKey
            , int loadSubChildNodesLevels)
        {
            XElement dataItem = me.DataContext as XElement;
            int decreasedLoadSubChildNodesLevels = loadSubChildNodesLevels - 1;
            var items = source.Where(x => x.Element(parentKey).Value == dataItem.Element(key).Value);
            if (items.Count() > 0) //不是叶子节点
            {
                foreach (var item in items)
                {
                    TreeViewItem tvi = new TreeViewItem();
                    if (item.Element("DefaultFlag").GetValue<int>(0) == 1)
                    {
                        tvi.FontWeight = FontWeights.Bold;
                    }

                    Binding bdDisplay = new Binding();
                    if (!string.IsNullOrEmpty(displayElementName))
                    {
                        bdDisplay.Path = new PropertyPath(string.Format("Element[{0}].Value", displayElementName));
                    }
                    if (!string.IsNullOrEmpty(converterParamenter))
                    {
                        bdDisplay.Converter = new XElementExpressionConverter();
                        bdDisplay.ConverterParameter = converterParamenter;
                    }
                    tvi.SetBinding(TreeViewItem.HeaderProperty, bdDisplay);
                    tvi.DataContext = item;
                    tvi.IsExpanded = true;
                    if (decreasedLoadSubChildNodesLevels > 0)
                    {
                        LoadSub_SetChildren(tvi, source, displayElementName, converterParamenter, key, parentKey, decreasedLoadSubChildNodesLevels);
                    }
                    me.Items.Add(tvi);
                }
            }
        }
        #endregion 

        /// <summary>
        /// 新增并刷新父节点
        /// </summary>
        /// <param name="me"></param>
        /// <param name="tree"></param>
        /// <param name="parentKey"></param>
        public static void RefreshParentOnInserting(this TreeViewItem me, TreeView tree, string parentKey)
        {
            ItemsControl parent;
            //树的第一层
            if (tree.SelectedItem == null || (me.DataContext as XElement).Element(parentKey).Value == "0")
            {
                parent = tree;
            }
            else if ((me.DataContext as XElement).Element(parentKey).Value
                == (tree.SelectedValue as XElement).Element(parentKey).Value)//添加同级
            {
                parent = (tree.SelectedItem as TreeViewItem).Parent as ItemsControl;
            }
            else//添加下级
            {
                parent = tree.SelectedItem as TreeViewItem;
                (parent as TreeViewItem).IsExpanded = true; //给一个节点添加下级节点后，确保该节点是展开着的
            }
            if ((me.DataContext as XElement).Element("DefaultFlag").GetValue<int>(0) == 1)
            {
                me.FontWeight = FontWeights.Bold;
            }
            else
            {
                me.FontWeight = FontWeights.Normal;
            }
            parent.AddChild(me);
            me.IsSelected = true;
        }

        /// <summary>
        /// 更新后自动刷新排序
        /// </summary>
        /// <param name="me"></param>
        public static void RefreshParentAfterUpdated(this TreeViewItem me)
        {
            if (me == null)
                return;
            if ((me.DataContext as XElement).Element("DefaultFlag").GetValue<int>(0) == 1)
            {
                me.FontWeight = FontWeights.Bold;
            }
            else
            {
                me.FontWeight = FontWeights.Normal;
            }

            (me as FrameworkElement).RefreshParentAfterUpdated();
            me.IsSelected = true;
        }

    }
}
